package com.finance.framework.qurtz;

import com.finance.framework.cache.concurrent.RedisLock;
import com.finance.framework.lang.Page;
import com.finance.scheduler.service.QuartzManager;
import com.finance.system.bean.JobStateDesciptor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by CBWL on 2017/6/5.
 */
public class RedisRunningStatusAcquirer implements SmartLifecycle {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private RedisTemplate redisTemplate;

    private boolean autoStartup = true;

    private boolean isRunning = false;

    private int phase = 2147483646;//此值比org.springframework.scheduling.quartz.SchedulerFactoryBean对应值小1个单位

    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    private QuartzManager quartzManager;

    public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory){
        this.autowireCapableBeanFactory = autowireCapableBeanFactory;
    }

    public void setQuartzManager(QuartzManager quartzManager){
        this.quartzManager = quartzManager;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
    }

     public Page acquirePage(TriggerKey triggerKey){
        return this.acquirePage(triggerKey,20);
    }

    private Page acquirePage(TriggerKey triggerKey,int seconds){
        this.logger.info("RunningStatusAcquirer:acquire ");
        final String lockName = triggerKey.getName() + triggerKey.getGroup();
        String pageStr = (String)this.redisTemplate.opsForList().leftPop(lockName,seconds,TimeUnit.SECONDS);
        if(StringUtils.isBlank(pageStr)) {
            return null;
        }
        String[] array = pageStr.split("\\*");
        if(ArrayUtils.isNotEmpty(array) && array.length == 2){
            Page page = Page.getInstance(Integer.valueOf(array[0]),Integer.valueOf(array[1]));
            return page;
        }
        return null;
    }

    public void putback(TriggerKey triggerKey,Page page){
        this.logger.info("RunningStatusAcquirer:putback ");
        String lockName = triggerKey.getName() + triggerKey.getGroup();
        ListOperations listOperations = redisTemplate.opsForList();
        String item = page.getPageSize() + "*" + page.getPageNo();
        if(page.getPageNo() > 5){
            listOperations.rightPush(lockName,item);
        }else{
            listOperations.leftPush(lockName,item);
        }
    }

    public void rebuildQueueMap(TriggerKey triggerKey){
        String lockName = triggerKey.getName() + triggerKey.getGroup();
         RedisLock lock = new RedisLock(redisTemplate, lockName, 10000, 20000);
        try {
            this.logger.info("锁{}准备加锁", lockName);
             if (lock.lock()) {
                 //此处以list取代 queue
                BoundListOperations boundListOperations = this.redisTemplate.boundListOps(lockName);
                redisTemplate.delete(lockName);
                 ListOperations listOperations = redisTemplate.opsForList();
                for(int i = 0;i < 30;i++){
                    String item = "1000*" + i;
                    listOperations.rightPush(lockName,item);
                 }
            }
        }catch (InterruptedException e){
            logger.error("锁" + lockName + e.getMessage(),e);
             Thread.currentThread().interrupt();
        }finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            if(lock.isLocked()) {
                lock.unlock();
            }
            this.logger.info("锁{}已释放",lockName);
         }
      }

    @Override
    public boolean isAutoStartup() {
        return this.autoStartup;
    }

    @Override
    public void stop(Runnable runnable) {
        runnable.run();
        this.isRunning = false;
    }

    @Override
    public void start() {
        isRunning = true;
        List<JobStateDesciptor> list = null;
        try {
            list = this.quartzManager.getAllJobStateDesciptor();
        } catch (Exception e) {
            this.logger.error(e.getMessage(),e);
        }
        if(CollectionUtils.isNotEmpty(list)){
            for(JobStateDesciptor jobStateDesciptor : list){
                 this.rebuildQueueMap(new TriggerKey(jobStateDesciptor.getTriggerName(),jobStateDesciptor.getTriggerGroupName()));
            }
        }
    }

    @Override
    public void stop() {
        this.isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return this.isRunning;
    }

    @Override
    public int getPhase() {
        return this.phase;
    }
}
